package cn.bluemobi.app.utils.wechatPay;

import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.StringReader;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.Iterator;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Random;

import org.apache.http.HttpResponse;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.client.params.ClientPNames;
import org.apache.http.conn.ClientConnectionManager;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.DefaultHttpClient;
import org.apache.http.util.EntityUtils;
import org.jdom.Document;
import org.jdom.Element;
import org.jdom.JDOMException;
import org.jdom.input.SAXBuilder;
import org.xml.sax.InputSource;

import cn.bluemobi.app.core.utils.PropertiesUtils;

/**
 * 微信支付
 * 
 * @author Chenwq
 * 
 */
public class WechatPayUtil {

    // public static void main(String[] args) {
    // Map<String, String> map =
    // WechatPayUtil.getOrderPaySn("20150928000000122", "38",
    // IpUtils.getLocalIp(),
    // "http://43.254.54.251:8088/jrx/appPay/wechatPaySuccess/" +
    // "20150928000000122" + ".htm");
    // String A =
    // "appid=wxd930ea5d5a258f4f&body=test&device_info=1000&mch_id=10000100&nonce_str=ibuaiVcKdpRxkhJA";
    // System.out.println(WeChatMd5.MD5Encode(A).toUpperCase());
    // int i = 0;
    // }

    /**
     * 获得订单交易信息
     * 
     * @param orderSn 订单号
     * @param amount 总金额
     * @param customerIp 客户IP
     * @return 订单交易信息
     */
    public static Map<String, String> getOrderPaySn(String orderSn, String amount, String customerIp) {

        Map<String, String> paramMap = new LinkedHashMap<String, String>();

        try {
            // 公众账号ID
            paramMap.put("appid", PropertiesUtils.getProperty("WECHAT_APPID"));

            // 简要描述
            paramMap.put("body", orderSn);

            // 币种
            paramMap.put("fee_type", "CNY");

            // 商户号
            paramMap.put("mch_id", PropertiesUtils.getProperty("WECHAT_MERCHANT_ID"));

            // 随机数
            paramMap.put("nonce_str", getNonceStr());

            // 回调地址
            paramMap.put("notify_url", PropertiesUtils.getProperty("WECHAR_CALL_BACK") + orderSn);

            // 商户订单号
            paramMap.put("out_trade_no", orderSn);

            // ip地址
            paramMap.put("spbill_create_ip", customerIp);

            // 总金额
            paramMap.put("total_fee", amount);

            // 交易方式，JSAPI，NATIVE，APP，
            paramMap.put("trade_type", "APP");

            // 密钥KEY
            // paramMap.put("key", PropertiesUtils.getProperty("WECHAT_KEY"));

            // 签名
            String sign = WeChatMd5.MD5Encode(serialize(paramMap));
            paramMap.put("sign", sign.toUpperCase());

            String requestXML = serializeXML(paramMap);

            return submitUrl(requestXML, "https://api.mch.weixin.qq.com/pay/unifiedorder");
        } catch (Exception e) {
            e.printStackTrace();
        }

        return paramMap;
    }

    /**
     * 生成随机数 nonce_str
     */
    private static String getNonceStr() {
        String letter[] = { "A", "B", "C", "D", "E", "F", "G", "H", "I", "J", "K", "L", "M", "N", "O", "P", "Q", "R",
                "S", "T", "U", "V", "W", "S", "Y", "Z" };
        String nonce_str = "";
        for (int i = 0; i < 20; i++) {
            int num = new Random().nextInt(26);
            nonce_str += letter[num];
        }
        return nonce_str;
    }

    /**
     * 序列化参数
     * 
     * @param params 参数map
     * @return 序列化值
     */
    private static String serialize(Map<String, String> params) {
        StringBuffer sb = new StringBuffer("");
        for (Iterator<String> iterator = params.keySet().iterator(); iterator.hasNext();) {
            String key = iterator.next();
            sb.append(key).append("=").append(params.get(key)).append(iterator.hasNext() ? "&" : "");
        }
        sb.append("&key=").append(PropertiesUtils.getProperty("WECHAT_KEY"));
        return sb.toString();
    }

    private static String serializeXML(Map<String, String> params) {
        StringBuffer sb = new StringBuffer("<xml>");
        for (Iterator<String> iterator = params.keySet().iterator(); iterator.hasNext();) {
            String key = iterator.next();
            sb.append("<").append(key).append(">").append(params.get(key)).append("</").append(key).append(">");
        }
        sb.append("</xml>");
        return sb.toString();
    }

    /**
     * java main方法 数据提交 提交到后台
     * 
     * @param contentData
     * @return 返回报文 map
     */
    private static Map<String, String> submitUrl(String xmlParams, String requestUrl) {
        Map<String, String> map = new HashMap<String, String>();

        DefaultHttpClient client = new DefaultHttpClient();
        client.getParams().setParameter(ClientPNames.ALLOW_CIRCULAR_REDIRECTS, true);

        HttpPost pmethod = new HttpPost(requestUrl); // 设置响应头信息
        pmethod.addHeader("Connection", "keep-alive");
        pmethod.addHeader("Accept", "*/*");
        pmethod.addHeader("Content-Type", "application/x-www-form-urlencoded; charset=UTF-8");
        pmethod.addHeader("Host", "api.mch.weixin.qq.com");
        pmethod.addHeader("X-Requested-With", "XMLHttpRequest");
        pmethod.addHeader("Cache-Control", "max-age=0");
        pmethod.addHeader("User-Agent", "Mozilla/4.0 (compatible; MSIE 8.0; Windows NT 6.0) ");

        try {
            DefaultHttpClient httpclient = new DefaultHttpClient();
            ClientConnectionManager ccm = httpclient.getConnectionManager();
            httpclient = new DefaultHttpClient(ccm, httpclient.getParams());

            pmethod.setEntity(new StringEntity(xmlParams, "UTF-8"));
            HttpResponse response = httpclient.execute(pmethod);
            String responseStr = EntityUtils.toString(response.getEntity(), "UTF-8");
            StringReader read = new StringReader(responseStr);
            // 创建新的输入源SAX 解析器将使用 InputSource 对象来确定如何读取 XML 输入
            InputSource source = new InputSource(read);
            // 创建一个新的SAXBuilder
            SAXBuilder sb = new SAXBuilder();
            // 通过输入源构造一个Document
            Document doc = sb.build(source);
            // 取的根元素
            Element root = doc.getRootElement();
            // 得到根元素所有子元素的集合
            List<?> jiedian = root.getChildren();
            for (int i = 0; i < jiedian.size(); i++) {
                Element et = (Element) jiedian.get(i);// 循环依次得到子元素
                map.put(et.getName(), et.getText());
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        return map;
    }

    /**
     * 解析xml,返回第一级元素键值对。如果第一级元素有子节点，则此节点的值是子节点的xml数据。
     * 
     * @param strxml
     * @return
     * @throws JDOMException
     * @throws IOException
     */
    public static Map<String, String> doXMLParse(String strxml) throws Exception {
        if (null == strxml || "".equals(strxml)) {
            return null;
        }

        Map<String, String> m = new HashMap<String, String>();
        InputStream in = new ByteArrayInputStream(strxml.getBytes());
        SAXBuilder builder = new SAXBuilder();
        Document doc = builder.build(in);
        Element root = doc.getRootElement();
        List<?> list = root.getChildren();
        Iterator<?> it = list.iterator();
        while (it.hasNext()) {
            Element e = (Element) it.next();
            String k = e.getName();
            String v = "";
            List<?> children = e.getChildren();
            if (children.isEmpty()) {
                v = e.getTextNormalize();
            } else {
                v = getChildrenText(children);
            }

            m.put(k, v);
        }

        // 关闭流
        in.close();
        return m;
    }

    /**
     * 获取子结点的xml
     * 
     * @param children
     * @return String
     */
    private static String getChildrenText(List<?> children) {
        StringBuffer sb = new StringBuffer();
        if (!children.isEmpty()) {
            Iterator<?> it = children.iterator();
            while (it.hasNext()) {
                Element e = (Element) it.next();
                String name = e.getName();
                String value = e.getTextNormalize();
                List<?> list = e.getChildren();
                sb.append("<" + name + ">");
                if (!list.isEmpty()) {
                    sb.append(getChildrenText(list));
                }
                sb.append(value);
                sb.append("</" + name + ">");
            }
        }
        return sb.toString();
    }

    /**
     * 验证签名是否正确
     */
    public static boolean validateSign(Map<String, String> map) {
        String sign1 = map.remove("sign");
        List<String> keys = new ArrayList<String>();
        keys.addAll(map.keySet());
        Collections.sort(keys);
        Map<String, String> newMap = new LinkedHashMap<String, String>();
        for (int i = 0; i < keys.size(); i++) {
            String key = keys.get(i);
            newMap.put(key, map.get(key));
        }
        String sign = WeChatMd5.MD5Encode(serialize(newMap)).toUpperCase();
        return sign1.equals(sign);
    }
}
